﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace K_Means
{
	class K_Means
	{
		private int _numClusters;
		private int _maxIterations;
		private List<AttributeDetails> _attributeDetails;
		private List<List<double>> _centers;
		private int[] _members;
		public int NumClusters
		{
			get
			{
				return this._numClusters;
			}
			set
			{
				this._numClusters = value;
			}
		}
		public int MaxIterations
		{
			get
			{
				return this._maxIterations;
			}
			set
			{
				this._maxIterations = value;
			}
		}
		public List<AttributeDetails> AttributeDetails
		{
			get
			{
				return this._attributeDetails;
			}
		}
		public List<List<double>> Centers
		{
			get
			{
				return this._centers;
			}
		}
		public int[] Members
		{
			get
			{
				return this._members;
			}
		}
		private const double THRESHOLD = 1.5;
		public K_Means()
		{
			this._attributeDetails = new List<AttributeDetails>();
			this._centers = new List<List<double>>();
			
		}

		public void Init()
		{
			this._members = new int[this._attributeDetails[0].Rows.Count];
			Random r = new Random();
			for (int i = 0; i < this._numClusters; i++) this._centers.Add(new List<double>());
			for (int i = 0; i < this._numClusters; i++)
			{
				bool next;
				int j = 0;
				do
				{
					next = false;
					j = r.Next(this._members.Length);
					if (i > 0)
					{
						for (int k = 0; k < i; k++)
						{
							if (GetDistance(k, j) > THRESHOLD) next = true;
						}
					}
					else next = true;
				}
				while (!next);
				if (next)
				{
					for (int k = 0; k < this._attributeDetails.Count; k++)
					{
						this._centers[i].Add(this._attributeDetails[k].Rows[j]);
					}
				}
				
			}
		}

		public void Start()
		{
			bool stop = true;
			int i = 0;
			int[] counts = new int[this._numClusters];
			double[,] sums = new double[this._numClusters, this._attributeDetails.Count];
			
			while (i < this._maxIterations)
			{
				stop = true;
				for (int j = 0; j < this._members.Length; j++)
				{
					double min = double.MaxValue;
					int o = this._members[j];
					for (int k = 0; k < this._numClusters; k++)
					{
						if (min > GetDistance(k, j))
						{
							min = GetDistance(k, j);
							this._members[j] = k;
						}
					}
					if (this._members[j] != o) stop = false;
				}
				for (int j = 0; j < counts.Length; j++) counts[j] = 0;
				for (int j = 0; j < this._numClusters; j++)
				{
					for (int k = 0; k < this._attributeDetails.Count; k++) sums[j, k] = 0.0;
				}
				for (int j = 0; j < this._members.Length; j++)
				{
					counts[this._members[j]]++;
					for (int k = 0; k < this._attributeDetails.Count; k++) sums[this._members[j], k] += this._attributeDetails[k].Rows[j];
				}
				for (int j = 0; j < this._numClusters; j++)
				{
					for (int k = 0; k < this._attributeDetails.Count; k++)
					{
						this._centers[j][k] = sums[j, k] / counts[j];
					}
				}
				i++;
				if (stop) break;
			}
			System.Windows.Forms.MessageBox.Show(i.ToString());
			for (int j = 0; j < this._attributeDetails.Count; j++)
			{
				double tmp = this._attributeDetails[j].Maximum - this._attributeDetails[j].Minimum;
				for (int k = 0; k < this._centers.Count; k++)
				{
					this._centers[k][j] = this._attributeDetails[j].Minimum + this._centers[k][j] * tmp;
				}
			}
		}
		public double GetDistance(int c, int j)
		{
			double distance = 0.0;
			for (int i = 0; i < this._attributeDetails.Count; i++)
			{
				distance += (this._attributeDetails[i].Rows[j] - this._centers[c][i]) * (this._attributeDetails[i].Rows[j] - this._centers[c][i]);
			}
			return distance;
		}
	}
}
